#include "rule.hpp"
#include "../utils/utils.hpp"

#include <algorithm>

namespace mashine { namespace kb {

using namespace std;

Rule::Rule() : Entity<Literal>("", vector<Literal>())
{
	undeniable = NULL;
	
	APP_LOGGER(info) << "Rule {" << toString() << "} instantiated";
}

Rule::Rule(vector<Literal> literals, string name) : Entity<Literal>(name, literals)
{
	undeniable = NULL;
	
	this->setParams(literals);
	
	APP_LOGGER(info) << "Rule {" << toString() << "} instantiated";
}

Rule::Rule(Rule const & rule) : Entity<Literal>(rule)
{
	undeniable = NULL;

	this->setParams(rule.getParams());
	
	APP_LOGGER(info) << "Rule {" << toString() << "} copied";
}

Rule::~Rule()
{
	// delete undeniable;
	APP_LOGGER(info) << "Rule {" << toString() << "} begins to break down";
}

void Rule::setParams(std::vector<Literal> params) {
	this->params = params;
	
	for (int i = 0; i < this->params.size(); ++i)
    {
		if (!this->params[i].isDenied())
		{
			undeniable = (this->undeniable == NULL) ? &(this->params[i]) : NULL;
		} 
    }
}

string Rule::toString() const
{
	if (undeniable == NULL) return "empty";
	
	string res;
	
	res.append(undeniable->toString());
	res.append("<-");
	
	vector<Literal>::const_iterator i;
    for (i = params.begin(); i != params.end(); i++)
    {
		if (undeniable != &(*i)) 
		{
			res.append( (~(*i)).toString() + ";" );
		}
    }
	
	if (params.size() != 0) res.erase(res.size() - 1, 1);
    
	return res;
}

/**
 * return string representation object
 */
Literal const * Rule::getUndeniableLiteral() const
{	
	return undeniable;
}

/**
 * set undeniable literal
 */	
void Rule::setUndeniableLiteral(Literal * undeniable)
{
	this->undeniable = undeniable;
}

/**
 * need owerride this method in child class 
 * to correct work Entity constructor
 */
bool Rule::validateName() const
{
	APP_LOGGER(info) << "Literal {" << toString() << "} params validating begin";

	return true;
}

/**
 * need owerride this method in child class 
 * to correct work Entity constructor
 */
bool Rule::validateParam() const
{
	APP_LOGGER(info) << "Literal {" << toString() << "} params validating begin";

	//TODO: add more details validation
	
	return true;
}

/**
 * replace paramethers in same order as in undenied predicate 
 */
Rule Rule::operator()(const vector<string> & params) const
{
	// TODO add condition this->params.size() == params.size()
	// build map
	map<string, string> p2p;
	
	vector<string>::const_iterator i = params.begin();
	BOOST_FOREACH(string s, undeniable->getParams())
	{
		if (utils::is_variable_name(s))
		{
			p2p[s] = *i;
			++i;
		}
	}
	
	Rule result;
	vector<Literal> lits;
	BOOST_FOREACH(const Literal & l, this->getParams())
	{	
		Literal nl;
		nl.setName(l.getName());
		nl.setDenied(l.isDenied());
		
		vector<string> nlp(l.getParams());
		for(int i = 0; i < l.getParams().size(); ++i)
		{
			if (utils::is_variable_name(l.getParams()[i]))
			{
				string replaceable(l.getParams()[i]);
				replace (nlp.begin(), nlp.end(), replaceable, p2p[replaceable]);
			}
		}
		
		nl.setParams(nlp);
		lits.push_back(nl);
	}
	
	std::cout << utils::vector_to_string<Literal>(lits) << "\n";
	
	result.setParams(lits);
	
	return result;
}

}}